package com.xiweicheng.test.proxy.resp.handler;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import com.xiweicheng.test.proxy.Constants;
import com.xiweicheng.test.proxy.MyX509TrustManager;
import com.xiweicheng.test.proxy.Utils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class RespHandler implements IRespHandler {

	@Override
	public void invoke(HttpServletRequest req, HttpServletResponse resp, String body) throws IOException {

		String baseUrl = Utils.getCookie(req, Constants.COOKIE_NAME_BASE_URL).getValue();

		String contextPath = req.getContextPath();
		String uri = req.getRequestURI();
		String query = req.getQueryString();

		String target = Utils.joinPaths(baseUrl, contextPath, uri)
				+ (StringUtils.isNotEmpty(query) ? ("?" + query) : "");

		log.debug("请求URL: {}", target);

		URL url = new URL(target);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();

		if (baseUrl.startsWith("https://")) {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext;
			try {
				sslContext = SSLContext.getInstance("SSL", "SunJSSE");
				sslContext.init(null, tm, new java.security.SecureRandom());
				// 从上述SSLContext对象中得到SSLSocketFactory对象
				SSLSocketFactory ssf = sslContext.getSocketFactory();

				((HttpsURLConnection) conn).setSSLSocketFactory(ssf);
			} catch (NoSuchAlgorithmException | NoSuchProviderException | KeyManagementException e) {
				e.printStackTrace();
				log.error("https连接请求设置加密认证失败！", e);
			}

		}

		this.setReqHeader(req, conn);

		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setRequestMethod(req.getMethod());
		conn.setUseCaches(false);
		conn.connect();

		this.setReqBody(body, conn);

		resp.setContentType(conn.getContentType());
		resp.setStatus(conn.getResponseCode());
		log.debug("Connection RespCode: {}", conn.getResponseCode());

		try {

			this.handle(conn, resp);

			this.setRespHeader(resp, conn);

		} finally {
			IOUtils.closeQuietly(conn.getInputStream());
			IOUtils.closeQuietly(resp.getOutputStream());
		}

	}

	protected void setReqHeader(HttpServletRequest req, HttpURLConnection conn) {

		Utils.setReqHeader(Utils.getHeaders(req), conn);
	}

	protected void setRespHeader(HttpServletResponse resp, HttpURLConnection conn) {

		Utils.setRespHeader(resp, conn.getHeaderFields());
	}

	protected void setReqBody(String body, HttpURLConnection conn) throws IOException {

		if (StringUtils.isEmpty(body)) {
			return;
		}

		try (OutputStream os = conn.getOutputStream()) {

			IOUtils.write(body, os, "UTF-8");

		}
	}

	protected abstract void handle(HttpURLConnection conn, HttpServletResponse resp) throws IOException;

}
